<template>
  <div class="container">
    <div class="container-header">
      <el-button type="primary" icon="Document" @click="handleSave">保存</el-button>
      <el-button type="success" icon="Right" @click="handleUsingTemplates">
        <!-- 使用模版 -->
        下一步
      </el-button>
    </div>
    <div class="container-content">
      <!-- 左侧 拖拽组件 -->
      <div class="left-board">
        <div class="logo-wrapper">
          <div class="logo">
            <img :src="logo" alt="logo" />
            <span class="ml20" v-if="!route.query.query">表单模版生成</span>
            <span class="ml20" v-else>选择表单模版</span>
          </div>
        </div>
        <el-scrollbar class="left-scrollbar">
          <div class="components-list">
            <!-- <div class="components-title"><svg-icon icon-class="component" />输入型组件</div> -->
            <draggable
              class="components-draggable"
              :list="inputComponents"
              :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
              :clone="cloneComponent"
              draggable=".components-item"
              :sort="false"
              @end="onEnd"
              item-key="label">
              <template #item="{ element, index }">
                <div :key="index" class="components-item" @click="addComponent(element)">
                  <div class="components-body">
                    <svg-icon :icon-class="element.tagIcon" />
                    {{ element.label }}
                  </div>
                </div>
              </template>
            </draggable>
            <!-- <div class="components-title"><svg-icon icon-class="component" />选择型组件</div> -->
            <draggable
              class="components-draggable"
              :list="selectComponents"
              :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
              :clone="cloneComponent"
              draggable=".components-item"
              :sort="false"
              @end="onEnd"
              item-key="label">
              <template #item="{ element, index }">
                <div :key="index" class="components-item" @click="addComponent(element)">
                  <div class="components-body">
                    <svg-icon :icon-class="element.tagIcon" />
                    {{ element.label }}
                  </div>
                </div>
              </template>
            </draggable>
            <!-- <div class="components-title"><svg-icon icon-class="component" /> 布局型组件</div> -->
            <draggable
              class="components-draggable"
              :list="layoutComponents"
              :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
              :clone="cloneComponent"
              draggable=".components-item"
              :sort="false"
              @end="onEnd"
              item-key="label">
              <template #item="{ element, index }">
                <div :key="index" class="components-item" @click="addComponent(element)">
                  <div class="components-body">
                    <svg-icon :icon-class="element.tagIcon" />
                    {{ element.label }}
                  </div>
                </div>
              </template>
            </draggable>
          </div>
        </el-scrollbar>
      </div>
      <!-- 内容 操作表单 -->
      <div class="center-board">
        <div class="action-bar">
          <!-- <el-button icon="Download" type="primary" text @click="download"> 导出vue文件 </el-button> -->
          <!-- <el-button class="copy-btn-main" icon="DocumentCopy" type="primary" text @click="copy"> 复制代码 </el-button> -->
          <!-- <el-button class="submit-btn" icon="Pointer" text @click="handleSave" type="primary"> 保存 </el-button> -->
          <el-button class="delete-btn" icon="Delete" text @click="empty" type="danger"> 清空 </el-button>
        </div>
        <el-scrollbar class="center-scrollbar">
          <el-row class="center-board-row" :gutter="formConf.gutter">
            <el-form :size="formConf.size" :label-position="formConf.labelPosition" :disabled="formConf.disabled" :label-width="formConf.labelWidth + 'px'">
              <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup" item-key="label">
                <template #item="{ element, index }">
                  <draggable-item
                    :key="element.renderKey"
                    :drawing-list="drawingList"
                    :element="element"
                    :index="index"
                    :active-id="activeId"
                    :form-conf="formConf"
                    @activeItem="activeFormItem"
                    @copyItem="drawingItemCopy"
                    @deleteItem="drawingItemDelete" />
                </template>
              </draggable>
              <div v-show="!drawingList.length" class="empty-info">从左侧拖入或点选组件进行模板设计</div>
            </el-form>
          </el-row>
        </el-scrollbar>
      </div>
      <!-- 右侧操作栏 -->
      <right-panel :active-data="activeData" :form-conf="formConf" :show-field="!!drawingList.length" @tag-change="tagChange" />

      <code-type-dialog v-model="dialogVisible" title="选择生成类型" :showFileName="showFileName" @confirm="generate" />
      <input id="copyNode" type="hidden" />
    </div>
  </div>
</template>

<script setup>
import draggable from "vuedraggable/dist/vuedraggable.common";
import ClipboardJS from "clipboard";
import beautifier from "js-beautify";
import logo from "@/assets/logo/logo.png";
import { inputComponents, selectComponents, layoutComponents, formConf as formConfData } from "./generator/config";
import { beautifierConf } from "@/utils/index";
import drawingDefalut from "./generator/drawingDefalut";
import { makeUpHtml, vueTemplate, vueScript, cssStyle } from "./generator/html";
import { makeUpJs } from "./generator/js";
import { makeUpCss } from "./generator/css";
import Download from "@/plugins/download";
import { ElNotification } from "element-plus";
import DraggableItem from "./components/DraggableItem";
import RightPanel from "./components/RightPanel";
import CodeTypeDialog from "./components/CodeTypeDialog";
import { onMounted, watch } from "vue";
const route = useRoute();

const drawingList = ref(drawingDefalut);
const { proxy } = getCurrentInstance();
const dialogVisible = ref(false);
const showFileName = ref(false);
const operationType = ref("");
const idGlobal = ref(100);
const activeData = ref(drawingDefalut[0]);
const activeId = ref(drawingDefalut[0].formId);
const generateConf = ref(null);
const formData = ref({});
const formConf = ref(formConfData);
let oldActiveId;
let tempActiveData;

// 选中表单 中 单项 操作
function activeFormItem(element) {
  activeData.value = element;
  activeId.value = element.formId;
}
// 复制代码 若依自带
function copy() {
  dialogVisible.value = true;
  showFileName.value = false;
  operationType.value = "copy";
}
// 导出模版 按钮
function download() {
  dialogVisible.value = true;
  showFileName.value = true;
  operationType.value = "download";
}
// 清空表单按钮
function empty() {
  proxy.$modal.confirm("确定要清空模版吗？", "提示", { type: "warning" }).then(() => {
    idGlobal.value = 100;
    drawingList.value = [];
  });
}
// 保存 表单 按钮
function handleSave() {
  proxy.$modal.confirm("确定要保存模版吗？", "提示", { type: "success" }).then(() => {
    proxy.$modal.msgSuccess("保存成功：调试中");
  });
}
function handleUsingTemplates() {
  console.log("drawingList", drawingList.value);
  let formArrDataNew = JSON.parse(JSON.stringify(drawingList.value));
  let formConfDataNew = JSON.parse(JSON.stringify(formConfData));
  if (formConfDataNew.formLabel === null) {
    proxy.$modal.msgSuccess("1111");
  }
}
// 表单 左侧 拖拽结束时触发
function onEnd(obj, a) {
  if (obj.from !== obj.to) {
    activeData.value = tempActiveData;
    activeId.value = idGlobal.value;
  }
}
// 表单 左侧 点击表单项触发
function addComponent(item) {
  const clone = cloneComponent(item);
  drawingList.value.push(clone);
  activeFormItem(clone);
}
// 表单 左侧 拖拽出来的事件
function cloneComponent(origin) {
  const clone = JSON.parse(JSON.stringify(origin));
  clone.formId = ++idGlobal.value;
  clone.span = formConf.value.span;
  clone.renderKey = +new Date(); // 改变renderKey后可以实现强制更新组件
  if (!clone.layout) clone.layout = "colFormItem";
  if (clone.layout === "colFormItem") {
    clone.vModel = `field${idGlobal.value}`;
    clone.placeholder !== undefined && (clone.placeholder += clone.label);
    tempActiveData = clone;
  } else if (clone.layout === "rowFormItem") {
    delete clone.label;
    clone.componentName = `row${idGlobal.value}`;
    clone.gutter = formConf.value.gutter;
    tempActiveData = clone;
  }
  return tempActiveData;
}
// 表单 复制操作（复制出来一个新的到最下面
function drawingItemCopy(item, parent) {
  let clone = JSON.parse(JSON.stringify(item));
  clone = createIdAndKey(clone);
  parent.push(clone);
  activeFormItem(clone);
}

function createIdAndKey(item) {
  item.formId = ++idGlobal.value;
  item.renderKey = +new Date();
  if (item.layout === "colFormItem") {
    item.vModel = `field${idGlobal.value}`;
  } else if (item.layout === "rowFormItem") {
    item.componentName = `row${idGlobal.value}`;
  }
  if (Array.isArray(item.children)) {
    item.children = item.children.map((childItem) => createIdAndKey(childItem));
  }
  return item;
}
// 表单 按钮中的删除（删除选中项）
function drawingItemDelete(index, parent) {
  console.log("drawingList", drawingList.value);
  parent.splice(index, 1);
  nextTick(() => {
    const len = drawingList.value.length;
    if (len) {
      activeFormItem(drawingList.value[len - 1]);
    }
  });
}
// 表单右侧 选择组件类型
function tagChange(newTag) {
  newTag = cloneComponent(newTag);
  newTag.vModel = activeData.value.vModel;
  newTag.formId = activeId.value;
  newTag.span = activeData.value.span;
  delete activeData.value.tag;
  delete activeData.value.tagIcon;
  delete activeData.value.document;
  Object.keys(newTag).forEach((key) => {
    if (activeData.value[key] !== undefined && typeof activeData.value[key] === typeof newTag[key]) {
      newTag[key] = activeData.value[key];
    }
  });
  activeData.value = newTag;
  updateDrawingList(newTag, drawingList.value);
}

function updateDrawingList(newTag, list) {
  const index = list.findIndex((item) => item.formId === activeId.value);
  if (index > -1) {
    list.splice(index, 1, newTag);
  } else {
    list.forEach((item) => {
      if (Array.isArray(item.children)) updateDrawingList(newTag, item.children);
    });
  }
}
// 选增生成类型 弹窗 确认回到
function generate(data) {
  generateConf.value = data;
  nextTick(() => {
    switch (operationType.value) {
      case "copy":
        execCopy(data);
        break;
      case "download":
        execDownload(data);
        break;
      default:
        break;
    }
  });
}
// 表单导出方法
function execDownload(data) {
  const codeStr = generateCode();
  const blob = new Blob([codeStr], { type: "text/plain;charset=utf-8" });
  Download.saveAs(blob, data.fileName);
}
// 表单复制方法
function execCopy(data) {
  document.getElementById("copyNode").click();
}
function AssembleFormData() {
  formData.value = { fields: JSON.parse(JSON.stringify(drawingList.value)), ...formConf.value };
}
function generateCode() {
  const { type } = generateConf.value;
  AssembleFormData();
  const script = vueScript(makeUpJs(formData.value, type));
  const html = vueTemplate(makeUpHtml(formData.value, type));
  const css = cssStyle(makeUpCss(formData.value));
  return beautifier.html(html + script + css, beautifierConf.html);
}
watch(
  () => activeData.value.label,
  (val, oldVal) => {
    if (activeData.value.placeholder === undefined || !activeData.value.tag || oldActiveId !== activeId.value) {
      return;
    }
    activeData.value.placeholder = activeData.value.placeholder.replace(oldVal, "") + val;
  }
);
watch(
  activeId,
  (val) => {
    oldActiveId = val;
  },
  { immediate: true }
);

onMounted(() => {
  // 复制成功的回调 （可以监听是否成功粘贴到剪贴板）
  const clipboard = new ClipboardJS("#copyNode", {
    text: (trigger) => {
      const codeStr = generateCode();
      ElNotification({ title: "成功", message: "代码已复制到剪切板，可粘贴。", type: "success" });
      return codeStr;
    },
  });
  clipboard.on("error", (e) => {
    proxy.$modal.msgError("代码复制失败");
  });
});
</script>

<style lang="scss">
$lighterBlue: #409eff;
.container {
  display: flex;
  flex-direction: column;
  .container-header {
    display: flex;
    justify-content: flex-end;
    background-color: #fff;
    height: 40px;
    button {
      height: 100%;
      width: 132px;
      display: block;
      border: 0;
      border-radius: 0;
      padding: 0;
      text-align: center;
      color: #fff !important;
      margin: 0;
    }
  }
  .container-content {
    position: relative;
    width: 100%;
    background-color: var(--el-bg-color-overlay);
    height: calc(100vh - 50px - 40px);
    overflow: hidden;

    .left-board {
      width: 260px;
      position: absolute;
      left: 0;
      top: 0;
      height: calc(100vh - 50px - 40px);

      .logo-wrapper {
        position: relative;
        height: 42px;
        border-bottom: 1px solid var(--el-border-color-extra-light);
        box-sizing: border-box;

        .logo {
          position: absolute;
          left: 12px;
          top: 6px;
          line-height: 30px;
          color: #00afff;
          font-weight: 600;
          font-size: 17px;
          white-space: nowrap;

          > img {
            width: 30px;
            height: 30px;
            vertical-align: top;
          }
          .github {
            display: inline-block;
            vertical-align: sub;
            margin-left: 15px;

            > img {
              height: 22px;
            }
          }
        }
      }

      .left-scrollbar {
        .el-scrollbar__wrap {
          box-sizing: border-box;
          overflow-x: hidden !important;
          margin-bottom: 0 !important;

          .components-list {
            padding: 8px;
            box-sizing: border-box;
            height: 100%;

            .components-title {
              font-size: 14px;
              // color: #222;
              margin: 6px 2px;

              .svg-icon {
                // color: #666;
                font-size: 18px;
                margin-right: 5px;
              }
            }

            .components-draggable {
              .components-item {
                display: inline-block;
                width: 48%;
                margin: 1%;
                transition: transform 0ms !important;

                .components-body {
                  padding: 8px 10px;
                  background: var(--el-border-color-extra-light);
                  font-size: 12px;
                  cursor: move;
                  border: 1px dashed var(--el-border-color-extra-light);
                  border-radius: 3px;

                  .svg-icon {
                    // color: #777;
                    font-size: 15px;
                    margin-right: 5px;
                  }

                  &:hover {
                    border: 1px dashed #787be8;
                    color: #787be8;

                    .svg-icon {
                      color: #787be8;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }

    .center-board {
      height: calc(100vh - 50px - 40px);
      width: auto;
      margin: 0 350px 0 260px;
      box-sizing: border-box;

      .action-bar {
        position: relative;
        height: 42px;
        padding: 0 15px;
        box-sizing: border-box;
        border: 1px solid var(--el-border-color-extra-light);
        border-top: none;
        border-left: none;
        display: flex;
        align-items: center;
        justify-content: flex-end;

        u .delete-btn {
          color: #f56c6c;
        }
      }

      .center-scrollbar {
        height: calc(100vh - 50px - 40px - 42px);
        overflow: hidden;
        border-left: 1px solid var(--el-border-color-extra-light);
        border-right: 1px solid var(--el-border-color-extra-light);
        box-sizing: border-box;

        .el-scrollbar__view {
          overflow-x: hidden;
        }

        .center-board-row {
          padding: 12px 12px 15px 12px;
          box-sizing: border-box;

          & > .el-form {
            // 69 = 12+15+42
            height: calc(100vh - 50px - 40px - 69px);
            flex: 1;

            .drawing-board {
              height: 100%;
              position: relative;

              .components-body {
                padding: 0;
                margin: 0;
                font-size: 0;
              }

              .sortable-ghost {
                position: relative;
                display: block;
                overflow: hidden;

                &::before {
                  content: " ";
                  position: absolute;
                  left: 0;
                  right: 0;
                  top: 0;
                  height: 3px;
                  background: rgb(89, 89, 223);
                  z-index: 2;
                }
              }

              .components-item.sortable-ghost {
                width: 100%;
                height: 60px;
                background: var(--el-border-color-extra-light);
              }

              .active-from-item {
                & > .el-form-item {
                  background: var(--el-border-color-extra-light);
                  border-radius: 6px;
                }

                & > .drawing-item-copy,
                & > .drawing-item-delete {
                  display: initial;
                }

                & > .component-name {
                  color: $lighterBlue;
                }

                .el-input__wrapper {
                  box-shadow: 0 0 0 1px var(--el-input-hover-border-color) inset;
                }
              }

              .el-form-item {
                margin-bottom: 15px;
              }
            }

            .drawing-item {
              position: relative;
              cursor: move;

              &.unfocus-bordered:not(.activeFromItem) > div:first-child {
                border: 1px dashed #ccc;
              }

              .el-form-item {
                padding: 12px 10px;
              }
            }

            .drawing-row-item {
              position: relative;
              cursor: move;
              box-sizing: border-box;
              border: 1px dashed #ccc;
              border-radius: 3px;
              padding: 0 2px;
              margin-bottom: 15px;

              .drawing-row-item {
                margin-bottom: 2px;
              }

              .el-col {
                margin-top: 22px;
              }

              .el-form-item {
                margin-bottom: 0;
              }

              .drag-wrapper {
                min-height: 80px;
                flex: 1;
                display: flex;
                flex-wrap: wrap;
              }

              &.active-from-item {
                border: 1px dashed $lighterBlue;
              }

              .component-name {
                position: absolute;
                top: 0;
                left: 0;
                font-size: 12px;
                color: #bbb;
                display: inline-block;
                padding: 0 6px;
              }
            }

            .drawing-item,
            .drawing-row-item {
              &:hover {
                & > .el-form-item {
                  background: var(--el-border-color-extra-light);
                  border-radius: 6px;
                }

                & > .drawing-item-copy,
                & > .drawing-item-delete {
                  display: initial;
                }
              }

              & > .drawing-item-copy,
              & > .drawing-item-delete {
                display: none;
                position: absolute;
                top: -10px;
                width: 22px;
                height: 22px;
                line-height: 22px;
                text-align: center;
                border-radius: 50%;
                font-size: 12px;
                border: 1px solid;
                cursor: pointer;
                z-index: 1;
              }

              & > .drawing-item-copy {
                right: 56px;
                border-color: $lighterBlue;
                color: $lighterBlue;
                background: #fff;

                &:hover {
                  background: $lighterBlue;
                  color: #fff;
                }
              }

              & > .drawing-item-delete {
                right: 24px;
                border-color: #f56c6c;
                color: #f56c6c;
                background: #fff;

                &:hover {
                  background: #f56c6c;
                  color: #fff;
                }
              }
            }

            .empty-info {
              position: absolute;
              top: 46%;
              left: 0;
              right: 0;
              text-align: center;
              font-size: 18px;
              color: #ccb1ea;
              letter-spacing: 4px;
            }
          }
        }
      }
    }
  }
}
</style>
